ISSUE-4336: EventLoop receives callbacks one event late when setting FuriEventFlag from interrupts#4358
Open
herbenderbler wants to merge 1 commit intoflipperdevices:devfrom
Conversation
08c72be to
d04eb58
Compare
d6a8e22 to
c00e2f2
Compare
…lipperdevices#4336) When furi_event_flag_set() was called from interrupt context, the event loop callback subscribed via furi_event_loop_subscribe_event_flag() could see the flag value one event late: the first wakeup often missed the first set, and subsequent wakeups reported the previous value. This made GPIO (and other ISR-driven) event flag usage unreliable. - Fix the event loop so the current flag state is observed on each wakeup with no one-event delay. - Export uxTopUsedPriority in the firmware API (furi_hal_os.h and api_symbols.csv) so FAPs that reference this FreeRTOS symbol load without "Missing Imports". - Add Step 5 verification docs for testing the fix with the EventFlag demo on a physical Flipper.
c00e2f2 to
210d39f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's New
Problem (fixes #4336)
When
furi_event_flag_set()was called from the interrupt context (e.g. GPIO) and the app usedfuri_event_loop_subscribe_event_flag(), the event loop saw events one step late:Cause
FreeRTOS’s
xEventGroupSetBitsFromISR()only queues the bit-set in the timer daemon. It does not set bits in the ISR. Furi then calledfuri_event_loop_link_notify()immediately, so the event loop woke before the timer task had applied the new bits. When the loop read the flag level, it saw the old (or zero) value.Fix
Notify the event loop only after the bits are set. In the ISR path of
furi_event_flag_set()we no longer usexEventGroupSetBitsFromISR()plus immediate notify. We usexTimerPendFunctionCallFromISR()to run a small callback in the timer daemon that:xEventGroupSetBits()furi_event_loop_link_notify()So when the event loop runs, the bits are already set and the callback sees the correct value. The timer command queue is unchanged. If it is full, we still return
FuriFlagErrorResource. Task-context behavior is unchanged.New documentation
documentation/Issue_4336_EventLoop_EventFlag_ISR_Review.md— Bug summary, root cause (including the previous code path), fix, workarounds, regression test reference, and a post-merge note with a suggested comment for the issue so the reporter can retest.furi/core/event_flag.handfuri/core/event_loop.h— State thatfuri_event_flag_set()is safe from ISR and thatfuri_event_loop_subscribe_event_flag()delivers the correct flag value with no one-event delay when set from interrupt context.unit_tests, flash, copy resources, rununit_testsorunit_tests test_furi, with a link to UnitTests.md.documentation/UnitTests.md— Example added for running a subset (e.g.unit_tests test_furi).documentation/FuriHalInterrupt.md— New HAL interrupt reference (init, set_isr, priorities,furi_hal_interrupt_trigger_pendingfor tests, get_name, get_time_in_isr_total); linked fromdocumentation/doxygen/system.dox.documentation/js/js_event_loop.md— Short note that the event loop is backed by Furi and that events from hardware interrupts are delivered with the correct value and order (no one-event delay), with a link to the issue and review doc.New tests and HAL
test_furi_event_loop_event_flag_from_isr()inapplications/debug/unit_tests/tests/furi/furi_event_loop_test.c— Uses a software-pending LPTIM2 interrupt to callfuri_event_flag_set()from ISR three times (bits 1, 2, 4) and asserts the event-loop callback receives each value in order. Would fail if the one-event-late bug returned. Run withunit_tests test_furion device.furi_hal_interrupt_trigger_pending(FuriHalInterruptId index)intargets/f7/furi_hal/furi_hal_interrupt.c— Sets the given interrupt pending so unit tests can run code in ISR context; used by the above test. Declared in the header and approved intargets/f7/api_symbols.csv(API 87.2).SubGhz Honeywell 5834-4 optimizations
This document describes the resource-conscious implementation choices for the Honeywell 5834-4 protocol added in the SubGhz: add Honeywell 5834-4 support commit. The Flipper Zero is an embedded device with limited RAM and flash; the following optimizations keep the new protocol lean.
1. Encoder upload buffer size
2. Read-only data in flash (const)
3. Minimal decoder state
4. Protocol type and flags
5. Single upload build, no per-repeat work
Summary
These choices align the Honeywell 5834-4 implementation with existing SubGhz protocols (e.g.
princeton.c,honeywell_wdb.c) and keep resource use appropriate for the Flipper Zero.Verification
./fbt -cthen./fbt copro_dist updater_package fap_dist) and unit-tests build (./fbt FIRMWARE_APP_SET=unit_tests resources) succeed../fbt -s lint,./fbt -s lint_img,./fbt -s lint_pypass./ext; device rebooted;python3 scripts/testops.py run_unitsrun (includestest_furi_event_loop_event_flag_from_isrin the Furi suite).Actions to verify bugfix
1. Build firmware with unit tests
From the firmware repo root:
Expected: Build completes with no errors;
build/latest/(or equivalent) contains firmware andbuild/latest/resources/contains resources.2. Flash unit-tests firmware to the device
Expected: Flash finishes successfully; device reboots into firmware that includes the
unit_testsapp.3. Copy resources to the Flipper SD card
Expected: All resource files (including unit test plugins) are sent to
/ext; script exits without error.4. Reboot the device (optional but recommended)
Wait a few seconds, then ensure the device is up (e.g. wait for it to appear again on USB/serial).
5. Run the Furi unit tests (regression test for #4336)
Ensure a CLI/serial session can be used (e.g. qFlipper CLI or
scripts/testops.py). Then run only the Furi tests:Option A – Using testops (recommended)
When prompted (or in the same session), run:
Option B – Manual CLI
Expected: All Furi tests pass, including
mu_test_furi_event_loop_event_flag_from_isr(or equivalent name fortest_furi_event_loop_event_flag_from_isr). No assertion failures or “one event late” errors.Failure that would indicate the bug: Test fails with wrong flag value (e.g. callback sees previous bit pattern), or timeout waiting for the event-flag callback.
6. (Optional) Run full unit test suite
Or from CLI:
Expected: Full suite completes; “Failed tests: 0” and “Status: PASSED” (or equivalent in your output). Confirms the fix doesn’t break other tests.
7. (Optional) Reproduce the original scenario (e.g. demo app)
If you have the reporter’s demo or a minimal app that uses GPIO (or other) interrupt →
furi_event_flag_set()→ event loop subscribed to that flag:FIRMWARE_APP_SET=unit_tests), or use a build that includes the demo.Reference: Issue #4336, demo repo: https://github.com/sorgloomer/flipper_eventflag_demo.
8. (Optional) Lint and full build sanity check
From repo root:
Expected: All builds and linters pass. Verifies the change doesn’t introduce build or style regressions.
Summary: minimum required to say “bug fix verified”
unit_tests test_furiand seetest_furi_event_loop_event_flag_from_isrpass).Optional but recommended: step 6 (full unit tests) and step 8 (clean build + linters). Step 7 is optional and only if you want to re-validate the exact original scenario (e.g. with the demo app).
Checklist (For Reviewer)